var SimpleTableInputMethod = InputMethod.extend({
	content_level: 0,
	content_total: 0,
	clv: 0,
	need_unicode_convert: true,
	/* max_key_length: (integer)
           maximum length of preedit (If the preedit length reachs this value, onComplete is called)
        */
	max_key_length: 0,
	auto_complete: true,
	long_table: false,
        // internal used for selection choice list
	current_list: null,
	target_list: 'Num',

	// reference to a GFCandidateList object
	candlist: null,

	constructor: function(clv)
	{
		this.base();
		var key;
		var i;

		// convert the char map
		if(this.need_unicode_convert) {
			for(key in this.GetClass().char_map) {
				this.GetClass().char_map[key] = lib.utf16char(this.GetClass().char_map[key]);
			}
		}
		this.clv = (!clv || clv > this.content_total) ? this.content_total : clv;
		this.content_level = 0;
	},
	init_module: function(ime,modman)
	{
		if(!this.base(ime,modman)) return false;
		if(this.content_level < this.clv) this.DownloadComponentStatic('table0');
		return true;
	},
	UpdateTable: function()
	{
		var i;
		var _this = this.GetClass();

		Debug.trace(1,"SimpleTableInputMethod: Update content level from %d...",this.content_level);
		for(this.content_level;;this.content_level++) {
			i = this.content_level;
			if(_this['table'+i]) {
				var key;
				var map = _this['table'+i];
				Debug.trace(1,"SimpleTableInputMethod: Content %d available...updating...",i);
				for(var key in map) {
					if(_this.table[key]) _this.table[key] = _this.table[key].concat(map[key]);
					else _this.table[key] = map[key];
				}
			}
			else break;
		}
		Debug.trace(1,"SimpleTableInputMethod: At Content level %d.",this.content_level);
		if(this.content_level < this.clv) this.DownloadComponentStatic(lib.sprintf('table%d',this.content_level));

	},
	onCompleteComponent: function(name)
	{
		var lv = parseInt(name.substr(5));
		var i;
		var _this = this.GetClass();

		Debug.trace(1,"SimpleTableInputMethod: Component %s download completed.",name);

		this.UpdateTable();
		if(this.ime.GetPreeditLength() > 0) {
			var key = this.ime.GetPreedit();
			this.current_list = this.GetClass().table[key];
			this.UpdateCandidate();
		}
	},
	onErrorComponent: function(name)
	{
		Debug.trace(0,"SimpleTableInputMethod: Component %s has errors.",name);
	},
	GetClass: function()
	{
		return SimpleTableInputMethod;
	},
	IsUseName: function()
	{
		return this.module_name() + '_';
	},
	module_name: function()
	{
		return 'SimpleTableInputMethod';
	},
	IMName: function()
	{
		return "SimpleTableInputMethod";
	},
	IsSelectionPreedit: function()
	{
		return true;
	},
	onSelectionModeResetPreedit: function()
	{
		this.onCancel();
	},
	keydown_handler: function(obj,key)
	{
		var b = true;
		switch(key) {
 		case 27: // Escape
			this.ime.ResetPreedit();
			b = false;
			break;
		case 8: // Backspace
			b = !this.onDeletePreedit(obj);
			break;
		default:
			break;
		}
		return b;
	},
	keypress_handler: function(obj,key,m)
	{
		var b = true;

		if(m != 0) return true;

		switch(key) {
/* After not_keypress code, escape has to be put in keydown_handler
 		case 27: // Escape
			Debug.present && Debug.trace(0,'Hello escape!');
			this.ime.ResetPreedit();
			b = false;
			break;
*/
		case 32: // Space
			if(this.candlist) {
				this.candlist.onNextPage(obj);
				b = false;
			}
			if(this.ime.GetPreeditLength() > 0) {
				this.onComplete(obj);
				b = false;
			}
			break;
		default:
			break;
		}

		if(!b) return false;

//		if(this.candlist) return false;

		if(this.ime.GetPreeditLength() >= this.max_key_length) return false;
		else {
			var ch = String.fromCharCode(key);
			var dch = this.GetClass().char_map[ch];

			if(dch) {
				if(this.candlist) this.candlist.onSelectCandidate(obj,1);
				this.ime.AppendPreedit(ch,dch,obj);
				Debug.trace(1,"SimpleTableInputMethod: Append Preedit (%s,%s)",ch,dch);
			}
			else {
				if(this.ime.GetPreeditLength() > 0) return false;
				else return true;
/*					if(this.IsSelectionPreedit()) this.onSelectionModeResetPreedit();
					return true;
*/
			}
	
			if(this.ime.GetPreeditLength() == this.max_key_length && this.auto_complete) {
				Debug.trace(1,"SimpleTableInputMethod: Auto-complete!");
				this.onComplete(obj);
			}
			return false;
		}
	},
	onActive: function()
	{
		this.current_list = null;
	},
	onDeactive: function()
	{
		this.current_list = null;
	},
	onDeletePreedit: function(obj)
	{
		if(this.ime.GetPreeditLength() > 0) {
			this.ime.DeletePreedit(1,1,obj);
			this.current_list = null;
			this.UpdateCandidate();
			return true;
		}
		else return false;
	},
	onCancel: function(obj)
	{
		this.ime.ResetPreedit();
		this.current_list = null;
		this.UpdateCandidate();
	},
	ListSelectHandler: function(obj,pos)
	{
		var ch;

		ch = this.current_list[pos];
		this.current_list = null;
		this.ime.ResetPreedit();
		this.UpdateCandidate();

		if(this.need_unicode_convert) {
			if(this.long_table) this.ime.SendString(obj,lib.utf16str(ch));
			else this.ime.SendString(obj,lib.utf16char(ch));
		}
		else this.ime.SendString(obj,ch);
		return true;
	},
	UpdateCandidate: function()
	{
		if(this.current_list) {
// Clear List is for unicode filtering
			var clear_list = new Array();

			var list = new Array();
			var i,j;
			var x = this;
			var loaddone = (this.content_level == this.content_total) ? true : false;
			var candlist;
			var update;

			if(this.need_unicode_convert) {
				for(i=0,j=0;i<this.current_list.length;i++) {
					if(GownFullBrowserDetect.isUnicodeVisible(this.current_list[i])) {
						clear_list[j] = this.current_list[i];
						list[j] = this.long_table ? lib.utf16str(clear_list[j]) : lib.utf16char(clear_list[j]);
						j++;
					}
					else {
						Debug.present && Debug.trace(2,'SimpleTableInputMethod: isUnicodeVisible filtered u+%x',this.current_list[i]);
					}
				}
				// replace current_list...
				this.current_list = clear_list;
			}
			else {
				for(i=0;i<this.current_list.length;i++) {
					list[i] = this.current_list[i];
				}
			}

			// check if candlist is already occupied...
			update = true;
			if(!this.candlist) {
				this.candlist = this.ime.candwin.OccupyList(this,this.target_list);
				update = false;
			}
			if(!this.candlist) {
				Debug.present && Debug.trace(0,'SimpleTableInputMethod: Require Target list %s is not available.',this.target_list);
				return;
			}
			
			if(update) {
				this.candlist.UpdateList(list);
			}
			else {
				this.candlist.ResetList();
				this.candlist.SetList(null,list,function(obj,pos) { return x.ListSelectHandler(obj,pos); });
				this.candlist.SetCancelHandler(function() { x.onCancel(null); return true; });
			}
			if(!loaddone) this.ime.candwin.SetStatus($GFS('More'));
			this.ime.candwin.UpdateCandidate();
		}
		else {
			if(this.candlist) {
				this.ime.candwin.ReleaseList(this,this.target_list);
				this.candlist = null;
			}
			this.ime.candwin.SetStatus(null);
			this.ime.candwin.UpdateCandidate();
		}
	},
	onComplete: function(obj)
	{
		var key = this.ime.GetPreedit();
		var list = this.GetClass().table[key];
		var loaddone = (this.content_level == this.content_total) ? true : false;

		if(!list) {
			Debug.trace(1,"SimpleTableInputMethod: No lists for key=\"%s\".",key);
			this.ime.InvalidatePreedit();
			return false;
		}
		if(list.length == 0 && loaddone) {
			Debug.trace(1,"SimpleTableInputMethod: Zero records found for key=\"%s\".",key);
			this.ime.InvalidatePreedit();
			return false;
		}
		else if(list.length == 1 && loaddone) {
			Debug.trace(1,"SimpleTableInputMethod: One record found for key=\"%s\".",key);
			this.ime.ResetPreedit();

			if(this.need_unicode_convert) {
				if(this.long_table) this.ime.SendString(obj,lib.utf16str(list[0]));
				else this.ime.SendString(obj,lib.utf16char(list[0]));
			}
			else this.ime.SendString(obj,list[0]);
			return true;
		}
		else {
			Debug.trace(1,"SimpleTableInputMethod: %d records found for key=\"%s\".",list.length,key);
			this.current_pos = 0;
			this.current_list = list;
			this.UpdateCandidate();
			return false;
		}
		return true;
	}
});
